home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * printf.c
- *
- * Copyright (c) 1991 Symantec Corporation. All rights reserved.
- *
- */
-
- #include "stdio.h"
- #include "stdarg.h"
- #include "string.h"
- #include "ansi_private.h"
- #include <SANE.h>
-
- #define BUFLEN 512
- #define TRUE 1
- #define FALSE 0
-
- static struct format {
- unsigned leftJustify : 1;
- unsigned forceSign : 1;
- unsigned altForm : 1;
- unsigned zeroPad : 1;
- unsigned havePrecision : 1;
- unsigned hSize : 1;
- unsigned lSize : 1;
- unsigned LSize : 1;
- char sign;
- char exponent;
- int fieldWidth;
- int precision;
- } default_format;
-
-
- struct decrec {
- char sgn;
- short exp;
- char sig[SIGDIGLEN];
- short pad;
- /* following fields aren't used by SANE */
- short min;
- short dot;
- short max;
- };
-
- static void ftod(int, int, struct decrec *, long double);
-
-
- int
- vfprintf(FILE *fp, const char *fmt, va_list arg)
- {
- register int c, i, j, nwritten = 0;
- register unsigned long n;
- long double x;
- register char *s;
- char buf[BUFLEN], *digits, *t;
- struct format F;
- struct decrec D;
-
- for (c = *fmt; c; c = *++fmt) {
- if (c != '%')
- goto copy1;
- F = default_format;
-
- /* decode flags */
-
- for (;;) {
- c = *++fmt;
- if (c == '-')
- F.leftJustify = TRUE;
- else if (c == '+')
- F.forceSign = TRUE;
- else if (c == ' ')
- F.sign = ' ';
- else if (c == '#')
- F.altForm = TRUE;
- else if (c == '0')
- F.zeroPad = TRUE;
- else
- break;
- }
-
- /* decode field width */
-
- if (c == '*') {
- if ((F.fieldWidth = va_arg(arg, int)) < 0) {
- F.leftJustify = TRUE;
- F.fieldWidth = -F.fieldWidth;
- }
- c = *++fmt;
- }
- else {
- for (; c >= '0' && c <= '9'; c = *++fmt)
- F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
- }
-
- /* decode precision */
-
- if (c == '.') {
- if ((c = *++fmt) == '*') {
- F.precision = va_arg(arg, int);
- c = *++fmt;
- }
- else {
- for (; c >= '0' && c <= '9'; c = *++fmt)
- F.precision = (10 * F.precision) + (c - '0');
- }
- if (F.precision >= 0)
- F.havePrecision = TRUE;
- }
-
- /* perform appropriate conversion */
-
- s = &buf[BUFLEN];
- if (F.leftJustify)
- F.zeroPad = FALSE;
- conv: switch (c) {
-
- /* 'h' size modifier */
-
- case 'h':
- F.hSize = TRUE;
- c = *++fmt;
- goto conv;
-
- /* 'l' size modifier */
-
- case 'l':
- F.lSize = TRUE;
- c = *++fmt;
- goto conv;
-
- /* 'L' size modifier */
-
- case 'L':
- F.LSize = TRUE;
- c = *++fmt;
- goto conv;
-
- /* decimal (signed) */
-
- case 'd':
- case 'i':
- if (F.lSize)
- n = va_arg(arg, long);
- else
- n = va_arg(arg, int);
- if (F.hSize)
- n = (short) n;
- if ((long) n < 0) {
- n = -n;
- F.sign = '-';
- }
- else if (F.forceSign)
- F.sign = '+';
- goto decimal;
-
- /* decimal (unsigned) */
-
- case 'u':
- if (F.lSize)
- n = va_arg(arg, unsigned long);
- else
- n = va_arg(arg, unsigned int);
- if (F.hSize)
- n = (unsigned short) n;
- F.sign = 0;
- goto decimal;
-
- /* decimal (common code) */
-
- decimal:
- if (!F.havePrecision) {
- if (F.zeroPad) {
- F.precision = F.fieldWidth;
- if (F.sign)
- --F.precision;
- }
- if (F.precision < 1)
- F.precision = 1;
- }
- for (i = 0; n; n /= 10, i++)
- *--s = n % 10 + '0';
- for (; i < F.precision; i++)
- *--s = '0';
- if (F.sign) {
- *--s = F.sign;
- i++;
- }
- break;
-
- /* octal (unsigned) */
-
- case 'o':
- if (F.lSize)
- n = va_arg(arg, unsigned long);
- else
- n = va_arg(arg, unsigned int);
- if (F.hSize)
- n = (unsigned short) n;
- if (!F.havePrecision) {
- if (F.zeroPad)
- F.precision = F.fieldWidth;
- if (F.precision < 1)
- F.precision = 1;
- }
- for (i = 0; n; n /= 8, i++)
- *--s = n % 8 + '0';
- if (F.altForm && i && *s != '0') {
- *--s = '0';
- i++;
- }
- for (; i < F.precision; i++)
- *--s = '0';
- break;
-
- /* hexadecimal (unsigned) */
-
- case 'p':
- F.havePrecision = F.lSize = TRUE;
- F.precision = 8;
- /* ... */
- case 'X':
- digits = "0123456789ABCDEF";
- goto hexadecimal;
- case 'x':
- digits = "0123456789abcdef";
- /* ... */
- hexadecimal:
- if (F.lSize)
- n = va_arg(arg, unsigned long);
- else
- n = va_arg(arg, unsigned int);
- if (F.hSize)
- n = (unsigned short) n;
- if (!F.havePrecision) {
- if (F.zeroPad) {
- F.precision = F.fieldWidth;
- if (F.altForm)
- F.precision -= 2;
- }
- if (F.precision < 1)
- F.precision = 1;
- }
- for (i = 0; n; n /= 16, i++)
- *--s = digits[n % 16];
- for (; i < F.precision; i++)
- *--s = '0';
- if (F.altForm) {
- *--s = c;
- *--s = '0';
- i += 2;
- }
- break;
-
- #ifndef _NOFLOATING_
- /* fixed-point */
-
- case 'f':
- if (F.LSize)
- x = va_arg(arg, long double);
- else
- x = va_arg(arg, double);
- if (!F.havePrecision)
- F.precision = 6;
- ftod(1, F.precision, &D, x);
- D.dot = D.exp + D.sig[0];
- if ((D.min = D.dot) > 1)
- D.min = 1;
- D.max = D.dot + F.precision;
- if (D.max - D.min > 508)
- memcpy(D.sig, "\6>>>>>>", 7);
- goto floating;
-
- /* floating-point */
-
- case 'e':
- case 'E':
- if (F.LSize)
- x = va_arg(arg, long double);
- else
- x = va_arg(arg, double);
- if (!F.havePrecision)
- F.precision = 6;
- F.exponent = c;
- ftod(0, D.max = F.precision + 1, &D, x);
- D.min = D.dot = 1;
- D.exp += D.sig[0] - 1;
- goto floating;
-
- /* "general" notation */
-
- case 'g':
- case 'G':
- if (F.LSize)
- x = va_arg(arg, long double);
- else
- x = va_arg(arg, double);
- if (!F.havePrecision)
- F.precision = 6;
- else if (F.precision == 0)
- F.precision = 1;
- F.exponent = c - 2;
- ftod(0, D.max = F.precision, &D, x);
- D.min = D.dot = 1;
- D.exp += D.sig[0] - 1;
- if (D.exp >= -4 && D.exp < F.precision) {
- F.exponent = 0;
- if ((D.dot += D.exp) < 1)
- D.min = D.dot;
- }
- if (!F.altForm && D.max > D.sig[0]) {
- if ((D.max = D.sig[0]) < D.dot)
- D.max = D.dot;
- }
- goto floating;
-
- /* floating (common code) */
-
- floating:
- if (D.sig[1] > '9') {
- F.exponent = FALSE;
- D.dot = 0;
- D.min = 1;
- D.max = D.sig[0];
- }
- i = 0;
- if (F.exponent) {
- n = D.exp < 0 ? -D.exp : D.exp;
- for (; n; n /= 10, i++)
- *--s = n % 10 + '0';
- for (; i < 2; i++)
- *--s = '0';
- *--s = D.exp < 0 ? '-' : '+';
- *--s = F.exponent;
- i += 2;
- }
- j = D.max;
- if (j == D.dot && !F.altForm)
- ++D.dot;
- do {
- if (j == D.dot) {
- *--s = '.';
- i++;
- }
- *--s = j > 0 && j <= D.sig[0] ? D.sig[j] : '0';
- } while (--j >= D.min);
- i += D.max - j;
- if (D.sgn)
- F.sign = '-';
- else if (F.forceSign)
- F.sign = '+';
- if (F.zeroPad) {
- j = F.fieldWidth;
- if (F.sign)
- --j;
- for (; i < j; i++)
- *--s = '0';
- }
- if (F.sign) {
- *--s = F.sign;
- i++;
- }
- break;
- #endif _NOFLOATING_
-
- /* character */
-
- case 'c':
- *--s = va_arg(arg, int);
- i = 1;
- break;
-
- /* string */
-
- case 's':
- s = va_arg(arg, char *);
- if (F.altForm) {
- i = (unsigned char) *s++;
- if (F.havePrecision && i > F.precision)
- i = F.precision;
- }
- else {
- if (!F.havePrecision)
- i = strlen(s);
- else if (t = memchr(s, '\0', F.precision))
- i = t - s;
- else
- i = F.precision;
- }
- break;
-
- /* store # bytes written so far */
-
- case 'n':
- s = va_arg(arg, void *);
- if (F.hSize)
- * (short *) s = nwritten;
- else if (F.lSize)
- * (long *) s = nwritten;
- else
- * (int *) s = nwritten;
- continue;
-
- /* oops - unknown conversion, abort */
-
- default:
- if (c != '%')
- goto done;
- copy1:
- if (putc(c, fp) < 0)
- return(EOF);
- ++nwritten;
- continue;
- }
-
- /* pad on the left */
-
- if (i < F.fieldWidth && !F.leftJustify) {
- do {
- if (putc(' ', fp) < 0)
- return(EOF);
- ++nwritten;
- } while (i < --F.fieldWidth);
- }
-
- /* write the converted result */
-
- if (fwrite(s, 1, i, fp) != i)
- return(EOF);
- nwritten += i;
-
- /* pad on the right */
-
- for (; i < F.fieldWidth; i++) {
- if (putc(' ', fp) < 0)
- return(EOF);
- ++nwritten;
- }
- }
-
- /* all done! */
-
- done:
- return(nwritten);
- }
-
-
- /* ---------- floating-point conversion ---------- */
-
- #ifndef _NOFLOATING_
- static void
- ftod(int fixed, int precision, struct decrec *d, long double x)
- {
- struct { char style; short digits; } form;
- int i;
- register short *p = (short *) &x;
-
- /* point to SANE extended */
-
- #if __option(mc68881) && __option(native_fp)
- p[1] = p[0];
- #endif
- #if __option(mc68881) || !__option(native_fp)
- p++;
- #endif
-
- /* convert to decimal record */
-
- if (precision >= sizeof d->sig)
- precision = sizeof d->sig - 1;
- form.style = fixed;
- form.digits = precision;
- fp68k(&form, p, d, (short)FX2DEC);
-
- /* handle fixed-point overflow */
-
- if (d->sig[1] == '?') {
- form.style = 0;
- form.digits = sizeof d->sig - 1;
- fp68k(&form, p, d, (short)FX2DEC);
- }
-
- /* strip trailing zeroes */
-
- for (i = d->sig[0]; i > 1 && d->sig[i] == '0'; --i)
- ++d->exp;
- d->sig[0] = i;
-
- /* format 0, INF, NAN */
-
- if (d->sig[1] == '0') {
- d->sgn = 0; /* delete to allow printing "-0" */
- d->exp = 0;
- }
- else if (d->sig[1] == 'I') {
- d->sig[0] = 3;
- d->sig[2] = 'N';
- d->sig[3] = 'F';
- }
- else if (d->sig[1] == 'N') {
- d->sig[0] = 5;
- d->sig[2] = 'A';
- d->sig[3] = 'N';
- }
- }
- #endif _NOFLOATING_
-